From b242b20898bd7966b4121ebef258ed8e42c80072 Mon Sep 17 00:00:00 2001 From: "kaf24@firebug.cl.cam.ac.uk" Date: Thu, 1 Dec 2005 11:27:27 +0100 Subject: [PATCH] Move net split driver onto ring.h generic rings. No backend should SHARED_RING_INIT(): that's the frontend's job. Signed-off-by: Keir Fraser --- linux-2.6-xen-sparse/arch/xen/Kconfig | 30 ++- .../arch/xen/configs/xen0_defconfig_x86_32 | 2 +- .../arch/xen/configs/xen0_defconfig_x86_64 | 2 +- .../arch/xen/configs/xenU_defconfig_x86_32 | 1 - .../arch/xen/configs/xenU_defconfig_x86_64 | 1 - .../arch/xen/configs/xen_defconfig_x86_32 | 2 +- .../arch/xen/configs/xen_defconfig_x86_64 | 2 +- .../drivers/xen/blkback/interface.c | 1 - .../drivers/xen/blktap/interface.c | 1 - .../drivers/xen/netback/common.h | 15 +- .../drivers/xen/netback/interface.c | 15 +- .../drivers/xen/netback/netback.c | 106 ++++++----- .../drivers/xen/netfront/netfront.c | 175 +++++++++--------- xen/include/public/io/netif.h | 53 +----- xen/include/public/io/ring.h | 7 +- 15 files changed, 200 insertions(+), 213 deletions(-) diff --git a/linux-2.6-xen-sparse/arch/xen/Kconfig b/linux-2.6-xen-sparse/arch/xen/Kconfig index 6912d1ce7d..8b3dd31e07 100644 --- a/linux-2.6-xen-sparse/arch/xen/Kconfig +++ b/linux-2.6-xen-sparse/arch/xen/Kconfig @@ -70,6 +70,19 @@ config XEN_NETDEV_BACKEND network devices to other guests via a high-performance shared-memory interface. +config XEN_NETDEV_PIPELINED_TRANSMITTER + bool "Pipelined transmitter (DANGEROUS)" + depends on XEN_NETDEV_BACKEND + default n + help + If the net backend is a dumb domain, such as a transparent Ethernet + bridge with no local IP interface, it is safe to say Y here to get + slightly lower network overhead. + If the backend has a local IP interface; or may be doing smart things + like reassembling packets to perform firewall filtering; or if you + are unsure; or if you experience network hangs when this option is + enabled; then you must say N here. + config XEN_TPMDEV_FRONTEND bool "TPM-device frontend driver" default n @@ -111,23 +124,6 @@ config XEN_NETDEV_FRONTEND dedicated device-driver domain, or your master control domain (domain 0), then you almost certainly want to say Y here. -config XEN_NETDEV_FRONTEND_PIPELINED_TRANSMITTER - bool "Pipelined transmitter (DANGEROUS)" - depends on XEN_NETDEV_FRONTEND - default n - help - The driver will assume that the backend is pipelining packets for - transmission: whenever packets are pending in the remote backend, - the driver will not send asynchronous notifications when it queues - additional packets for transmission. - If the backend is a dumb domain, such as a transparent Ethernet - bridge with no local IP interface, it is safe to say Y here to get - slightly lower network overhead. - If the backend has a local IP interface; or may be doing smart things - like reassembling packets to perform firewall filtering; or if you - are unsure; or if you experience network hangs when this option is - enabled; then you must say N here. - config XEN_BLKDEV_TAP bool "Block device tap driver" default n diff --git a/linux-2.6-xen-sparse/arch/xen/configs/xen0_defconfig_x86_32 b/linux-2.6-xen-sparse/arch/xen/configs/xen0_defconfig_x86_32 index 1370fc77d8..763c5bf96a 100644 --- a/linux-2.6-xen-sparse/arch/xen/configs/xen0_defconfig_x86_32 +++ b/linux-2.6-xen-sparse/arch/xen/configs/xen0_defconfig_x86_32 @@ -15,11 +15,11 @@ CONFIG_XEN_PHYSDEV_ACCESS=y CONFIG_XEN_BLKDEV_BACKEND=y # CONFIG_XEN_BLKDEV_TAP_BE is not set CONFIG_XEN_NETDEV_BACKEND=y +# CONFIG_XEN_NETDEV_PIPELINED_TRANSMITTER is not set # CONFIG_XEN_TPMDEV_FRONTEND is not set # CONFIG_XEN_TPMDEV_BACKEND is not set CONFIG_XEN_BLKDEV_FRONTEND=y CONFIG_XEN_NETDEV_FRONTEND=y -# CONFIG_XEN_NETDEV_FRONTEND_PIPELINED_TRANSMITTER is not set # CONFIG_XEN_BLKDEV_TAP is not set # CONFIG_XEN_SHADOW_MODE is not set CONFIG_XEN_SCRUB_PAGES=y diff --git a/linux-2.6-xen-sparse/arch/xen/configs/xen0_defconfig_x86_64 b/linux-2.6-xen-sparse/arch/xen/configs/xen0_defconfig_x86_64 index 70897076f9..4f0c03d416 100644 --- a/linux-2.6-xen-sparse/arch/xen/configs/xen0_defconfig_x86_64 +++ b/linux-2.6-xen-sparse/arch/xen/configs/xen0_defconfig_x86_64 @@ -15,11 +15,11 @@ CONFIG_XEN_PHYSDEV_ACCESS=y CONFIG_XEN_BLKDEV_BACKEND=y # CONFIG_XEN_BLKDEV_TAP_BE is not set CONFIG_XEN_NETDEV_BACKEND=y +# CONFIG_XEN_NETDEV_PIPELINED_TRANSMITTER is not set # CONFIG_XEN_TPMDEV_FRONTEND is not set # CONFIG_XEN_TPMDEV_BACKEND is not set CONFIG_XEN_BLKDEV_FRONTEND=y CONFIG_XEN_NETDEV_FRONTEND=y -# CONFIG_XEN_NETDEV_FRONTEND_PIPELINED_TRANSMITTER is not set # CONFIG_XEN_BLKDEV_TAP is not set # CONFIG_XEN_SHADOW_MODE is not set CONFIG_XEN_SCRUB_PAGES=y diff --git a/linux-2.6-xen-sparse/arch/xen/configs/xenU_defconfig_x86_32 b/linux-2.6-xen-sparse/arch/xen/configs/xenU_defconfig_x86_32 index a4e9d33376..8b1749b253 100644 --- a/linux-2.6-xen-sparse/arch/xen/configs/xenU_defconfig_x86_32 +++ b/linux-2.6-xen-sparse/arch/xen/configs/xenU_defconfig_x86_32 @@ -16,7 +16,6 @@ CONFIG_NO_IDLE_HZ=y # CONFIG_XEN_TPMDEV_BACKEND is not set CONFIG_XEN_BLKDEV_FRONTEND=y CONFIG_XEN_NETDEV_FRONTEND=y -# CONFIG_XEN_NETDEV_FRONTEND_PIPELINED_TRANSMITTER is not set # CONFIG_XEN_BLKDEV_TAP is not set # CONFIG_XEN_SHADOW_MODE is not set CONFIG_XEN_SCRUB_PAGES=y diff --git a/linux-2.6-xen-sparse/arch/xen/configs/xenU_defconfig_x86_64 b/linux-2.6-xen-sparse/arch/xen/configs/xenU_defconfig_x86_64 index 7e9d1a5888..6e2775e24f 100644 --- a/linux-2.6-xen-sparse/arch/xen/configs/xenU_defconfig_x86_64 +++ b/linux-2.6-xen-sparse/arch/xen/configs/xenU_defconfig_x86_64 @@ -16,7 +16,6 @@ CONFIG_NO_IDLE_HZ=y # CONFIG_XEN_TPMDEV_BACKEND is not set CONFIG_XEN_BLKDEV_FRONTEND=y CONFIG_XEN_NETDEV_FRONTEND=y -# CONFIG_XEN_NETDEV_FRONTEND_PIPELINED_TRANSMITTER is not set # CONFIG_XEN_BLKDEV_TAP is not set # CONFIG_XEN_SHADOW_MODE is not set CONFIG_XEN_SCRUB_PAGES=y diff --git a/linux-2.6-xen-sparse/arch/xen/configs/xen_defconfig_x86_32 b/linux-2.6-xen-sparse/arch/xen/configs/xen_defconfig_x86_32 index cf50b8aac1..04403f1a20 100644 --- a/linux-2.6-xen-sparse/arch/xen/configs/xen_defconfig_x86_32 +++ b/linux-2.6-xen-sparse/arch/xen/configs/xen_defconfig_x86_32 @@ -15,11 +15,11 @@ CONFIG_XEN_PHYSDEV_ACCESS=y CONFIG_XEN_BLKDEV_BACKEND=y # CONFIG_XEN_BLKDEV_TAP_BE is not set CONFIG_XEN_NETDEV_BACKEND=y +# CONFIG_XEN_NETDEV_PIPELINED_TRANSMITTER is not set # CONFIG_XEN_TPMDEV_FRONTEND is not set # CONFIG_XEN_TPMDEV_BACKEND is not set CONFIG_XEN_BLKDEV_FRONTEND=y CONFIG_XEN_NETDEV_FRONTEND=y -# CONFIG_XEN_NETDEV_FRONTEND_PIPELINED_TRANSMITTER is not set # CONFIG_XEN_BLKDEV_TAP is not set # CONFIG_XEN_SHADOW_MODE is not set CONFIG_XEN_SCRUB_PAGES=y diff --git a/linux-2.6-xen-sparse/arch/xen/configs/xen_defconfig_x86_64 b/linux-2.6-xen-sparse/arch/xen/configs/xen_defconfig_x86_64 index d5c01d3a6f..cea13495a4 100644 --- a/linux-2.6-xen-sparse/arch/xen/configs/xen_defconfig_x86_64 +++ b/linux-2.6-xen-sparse/arch/xen/configs/xen_defconfig_x86_64 @@ -15,11 +15,11 @@ CONFIG_XEN_PHYSDEV_ACCESS=y CONFIG_XEN_BLKDEV_BACKEND=y # CONFIG_XEN_BLKDEV_TAP_BE is not set CONFIG_XEN_NETDEV_BACKEND=y +# CONFIG_XEN_NETDEV_PIPELINED_TRANSMITTER is not set # CONFIG_XEN_TPMDEV_FRONTEND is not set # CONFIG_XEN_TPMDEV_BACKEND is not set CONFIG_XEN_BLKDEV_FRONTEND=y CONFIG_XEN_NETDEV_FRONTEND=y -# CONFIG_XEN_NETDEV_FRONTEND_PIPELINED_TRANSMITTER is not set # CONFIG_XEN_BLKDEV_TAP is not set # CONFIG_XEN_SHADOW_MODE is not set CONFIG_XEN_SCRUB_PAGES=y diff --git a/linux-2.6-xen-sparse/drivers/xen/blkback/interface.c b/linux-2.6-xen-sparse/drivers/xen/blkback/interface.c index 15474a3205..080f1a8e17 100644 --- a/linux-2.6-xen-sparse/drivers/xen/blkback/interface.c +++ b/linux-2.6-xen-sparse/drivers/xen/blkback/interface.c @@ -107,7 +107,6 @@ int blkif_map(blkif_t *blkif, unsigned long shared_page, unsigned int evtchn) blkif->evtchn = op.u.bind_interdomain.local_port; sring = (blkif_sring_t *)blkif->blk_ring_area->addr; - SHARED_RING_INIT(sring); BACK_RING_INIT(&blkif->blk_ring, sring, PAGE_SIZE); blkif->irq = bind_evtchn_to_irqhandler( diff --git a/linux-2.6-xen-sparse/drivers/xen/blktap/interface.c b/linux-2.6-xen-sparse/drivers/xen/blktap/interface.c index 58f30b0cfd..3e76ab2100 100644 --- a/linux-2.6-xen-sparse/drivers/xen/blktap/interface.c +++ b/linux-2.6-xen-sparse/drivers/xen/blktap/interface.c @@ -97,7 +97,6 @@ int blkif_map(blkif_t *blkif, unsigned long shared_page, unsigned int evtchn) blkif->evtchn = op.u.bind_interdomain.local_port; sring = (blkif_sring_t *)blkif->blk_ring_area->addr; - SHARED_RING_INIT(sring); BACK_RING_INIT(&blkif->blk_ring, sring, PAGE_SIZE); blkif->irq = bind_evtchn_to_irqhandler( diff --git a/linux-2.6-xen-sparse/drivers/xen/netback/common.h b/linux-2.6-xen-sparse/drivers/xen/netback/common.h index e1c5bd204f..f1d4533d98 100644 --- a/linux-2.6-xen-sparse/drivers/xen/netback/common.h +++ b/linux-2.6-xen-sparse/drivers/xen/netback/common.h @@ -53,16 +53,12 @@ typedef struct netif_st { unsigned int irq; /* The shared rings and indexes. */ - netif_tx_interface_t *tx; - netif_rx_interface_t *rx; + netif_tx_back_ring_t tx; + netif_rx_back_ring_t rx; struct vm_struct *comms_area; - /* Private indexes into shared ring. */ - NETIF_RING_IDX rx_req_cons; - NETIF_RING_IDX rx_resp_prod; /* private version of shared variable */ - NETIF_RING_IDX rx_resp_prod_copy; - NETIF_RING_IDX tx_req_cons; - NETIF_RING_IDX tx_resp_prod; /* private version of shared variable */ + /* Allow netif_be_start_xmit() to peek ahead in the rx request ring. */ + RING_IDX rx_req_cons_peek; /* Transmit shaping: allow 'credit_bytes' every 'credit_usec'. */ unsigned long credit_bytes; @@ -81,6 +77,9 @@ typedef struct netif_st { struct work_struct free_work; } netif_t; +#define NET_TX_RING_SIZE __RING_SIZE((netif_tx_sring_t *)0, PAGE_SIZE) +#define NET_RX_RING_SIZE __RING_SIZE((netif_rx_sring_t *)0, PAGE_SIZE) + void netif_creditlimit(netif_t *netif); int netif_disconnect(netif_t *netif); diff --git a/linux-2.6-xen-sparse/drivers/xen/netback/interface.c b/linux-2.6-xen-sparse/drivers/xen/netback/interface.c index f4682750cb..23661ababc 100644 --- a/linux-2.6-xen-sparse/drivers/xen/netback/interface.c +++ b/linux-2.6-xen-sparse/drivers/xen/netback/interface.c @@ -184,6 +184,8 @@ int netif_map(netif_t *netif, unsigned long tx_ring_ref, unsigned long rx_ring_ref, unsigned int evtchn) { int err; + netif_tx_sring_t *txs; + netif_rx_sring_t *rxs; evtchn_op_t op = { .cmd = EVTCHNOP_bind_interdomain, .u.bind_interdomain.remote_dom = netif->domid, @@ -216,10 +218,15 @@ int netif_map(netif_t *netif, unsigned long tx_ring_ref, netif->evtchn, netif_be_int, 0, netif->dev->name, netif); disable_irq(netif->irq); - netif->tx = (netif_tx_interface_t *)netif->comms_area->addr; - netif->rx = (netif_rx_interface_t *) + txs = (netif_tx_sring_t *)netif->comms_area->addr; + BACK_RING_INIT(&netif->tx, txs, PAGE_SIZE); + + rxs = (netif_rx_sring_t *) ((char *)netif->comms_area->addr + PAGE_SIZE); - netif->tx->resp_prod = netif->rx->resp_prod = 0; + BACK_RING_INIT(&netif->rx, rxs, PAGE_SIZE); + + netif->rx_req_cons_peek = 0; + netif_get(netif); wmb(); /* Other CPUs see new state before interface is started. */ @@ -246,7 +253,7 @@ static void free_netif_callback(void *arg) unregister_netdev(netif->dev); - if (netif->tx) { + if (netif->tx.sring) { unmap_frontend_pages(netif); free_vm_area(netif->comms_area); } diff --git a/linux-2.6-xen-sparse/drivers/xen/netback/netback.c b/linux-2.6-xen-sparse/drivers/xen/netback/netback.c index 0440aa4342..c8e8ad7dd2 100644 --- a/linux-2.6-xen-sparse/drivers/xen/netback/netback.c +++ b/linux-2.6-xen-sparse/drivers/xen/netback/netback.c @@ -38,8 +38,8 @@ static struct timer_list net_timer; #define MAX_PENDING_REQS 256 static struct sk_buff_head rx_queue; -static multicall_entry_t rx_mcl[NETIF_RX_RING_SIZE*2+1]; -static mmu_update_t rx_mmu[NETIF_RX_RING_SIZE]; +static multicall_entry_t rx_mcl[NET_RX_RING_SIZE*2+1]; +static mmu_update_t rx_mmu[NET_RX_RING_SIZE]; static gnttab_transfer_t grant_rx_op[MAX_PENDING_REQS]; static unsigned char rx_notify[NR_IRQS]; @@ -126,8 +126,9 @@ int netif_be_start_xmit(struct sk_buff *skb, struct net_device *dev) /* Drop the packet if the target domain has no receive buffers. */ if (!netif->active || - (netif->rx_req_cons == netif->rx->req_prod) || - ((netif->rx_req_cons-netif->rx_resp_prod) == NETIF_RX_RING_SIZE)) + (netif->rx_req_cons_peek == netif->rx.sring->req_prod) || + ((netif->rx_req_cons_peek - netif->rx.rsp_prod_pvt) == + NET_RX_RING_SIZE)) goto drop; /* @@ -154,7 +155,7 @@ int netif_be_start_xmit(struct sk_buff *skb, struct net_device *dev) skb = nskb; } - netif->rx_req_cons++; + netif->rx_req_cons_peek++; netif_get(netif); skb_queue_tail(&rx_queue, skb); @@ -198,7 +199,7 @@ static void net_rx_action(unsigned long unused) unsigned long vdata, old_mfn, new_mfn; struct sk_buff_head rxq; struct sk_buff *skb; - u16 notify_list[NETIF_RX_RING_SIZE]; + u16 notify_list[NET_RX_RING_SIZE]; int notify_nr = 0; int ret; @@ -233,9 +234,9 @@ static void net_rx_action(unsigned long unused) gop->mfn = old_mfn; gop->domid = netif->domid; - gop->ref = netif->rx->ring[ - MASK_NETIF_RX_IDX(netif->rx_resp_prod_copy)].req.gref; - netif->rx_resp_prod_copy++; + gop->ref = RING_GET_REQUEST( + &netif->rx, netif->rx.req_cons)->gref; + netif->rx.req_cons++; gop++; mmu->ptr = ((maddr_t)new_mfn << PAGE_SHIFT) | @@ -300,8 +301,7 @@ static void net_rx_action(unsigned long unused) status = NETIF_RSP_ERROR; } irq = netif->irq; - id = netif->rx->ring[ - MASK_NETIF_RX_IDX(netif->rx_resp_prod)].req.id; + id = RING_GET_REQUEST(&netif->rx, netif->rx.rsp_prod_pvt)->id; if (make_rx_response(netif, id, status, (unsigned long)skb->data & ~PAGE_MASK, size, skb->proto_csum_valid) && @@ -371,13 +371,31 @@ static void add_to_net_schedule_list_tail(netif_t *netif) spin_unlock_irq(&net_schedule_list_lock); } +/* + * Note on CONFIG_XEN_NETDEV_PIPELINED_TRANSMITTER: + * If this driver is pipelining transmit requests then we can be very + * aggressive in avoiding new-packet notifications -- frontend only needs to + * send a notification if there are no outstanding unreceived responses. + * If we may be buffer transmit buffers for any reason then we must be rather + * more conservative and advertise that we are 'sleeping' this connection here. + */ void netif_schedule_work(netif_t *netif) { - if ((netif->tx_req_cons != netif->tx->req_prod) && - ((netif->tx_req_cons-netif->tx_resp_prod) != NETIF_TX_RING_SIZE)) { + if (RING_HAS_UNCONSUMED_REQUESTS(&netif->tx)) { add_to_net_schedule_list_tail(netif); maybe_schedule_tx_action(); } +#ifndef CONFIG_XEN_NETDEV_PIPELINED_TRANSMITTER + else { + netif->tx.sring->server_is_sleeping = 1; + mb(); + if (RING_HAS_UNCONSUMED_REQUESTS(&netif->tx)) { + netif->tx.sring->server_is_sleeping = 0; + add_to_net_schedule_list_tail(netif); + maybe_schedule_tx_action(); + } + } +#endif } void netif_deschedule_work(netif_t *netif) @@ -437,11 +455,18 @@ inline static void net_tx_action_dealloc(void) * packets. */ mb(); - if ((netif->tx_req_cons != netif->tx->req_prod) && - ((netif->tx_req_cons-netif->tx_resp_prod) != - NETIF_TX_RING_SIZE)) + + if (RING_HAS_UNCONSUMED_REQUESTS(&netif->tx)) { add_to_net_schedule_list_tail(netif); - + } else { + netif->tx.sring->server_is_sleeping = 1; + mb(); + if (RING_HAS_UNCONSUMED_REQUESTS(&netif->tx)) { + netif->tx.sring->server_is_sleeping = 0; + add_to_net_schedule_list_tail(netif); + } + } + netif_put(netif); } } @@ -454,7 +479,7 @@ static void net_tx_action(unsigned long unused) netif_t *netif; netif_tx_request_t txreq; u16 pending_idx; - NETIF_RING_IDX i; + RING_IDX i; gnttab_map_grant_ref_t *mop; unsigned int data_len; int ret; @@ -472,16 +497,14 @@ static void net_tx_action(unsigned long unused) remove_from_net_schedule_list(netif); /* Work to do? */ - i = netif->tx_req_cons; - if ((i == netif->tx->req_prod) || - ((i-netif->tx_resp_prod) == NETIF_TX_RING_SIZE)) { + if (!RING_HAS_UNCONSUMED_REQUESTS(&netif->tx)) { netif_put(netif); continue; } + i = netif->tx.req_cons; rmb(); /* Ensure that we see the request before we copy it. */ - memcpy(&txreq, &netif->tx->ring[MASK_NETIF_TX_IDX(i)].req, - sizeof(txreq)); + memcpy(&txreq, RING_GET_REQUEST(&netif->tx, i), sizeof(txreq)); /* Credit-based scheduling. */ if (txreq.size > netif->remaining_credit) { unsigned long now = jiffies; @@ -515,12 +538,7 @@ static void net_tx_action(unsigned long unused) } netif->remaining_credit -= txreq.size; - /* - * Why the barrier? It ensures that the frontend sees updated - * req_cons before we check for more work to schedule. - */ - netif->tx->req_cons = ++netif->tx_req_cons; - mb(); + netif->tx.req_cons++; netif_schedule_work(netif); @@ -688,17 +706,18 @@ static void make_tx_response(netif_t *netif, u16 id, s8 st) { - NETIF_RING_IDX i = netif->tx_resp_prod; + RING_IDX i = netif->tx.rsp_prod_pvt; netif_tx_response_t *resp; - resp = &netif->tx->ring[MASK_NETIF_TX_IDX(i)].resp; + resp = RING_GET_RESPONSE(&netif->tx, i); resp->id = id; resp->status = st; wmb(); - netif->tx->resp_prod = netif->tx_resp_prod = ++i; + netif->tx.rsp_prod_pvt = ++i; + RING_PUSH_RESPONSES(&netif->tx); mb(); /* Update producer before checking event threshold. */ - if (i == netif->tx->event) + if (i == netif->tx.sring->rsp_event) notify_remote_via_irq(netif->irq); } @@ -709,10 +728,10 @@ static int make_rx_response(netif_t *netif, u16 size, u16 csum_valid) { - NETIF_RING_IDX i = netif->rx_resp_prod; + RING_IDX i = netif->rx.rsp_prod_pvt; netif_rx_response_t *resp; - resp = &netif->rx->ring[MASK_NETIF_RX_IDX(i)].resp; + resp = RING_GET_RESPONSE(&netif->rx, i); resp->offset = offset; resp->csum_valid = csum_valid; resp->id = id; @@ -720,10 +739,11 @@ static int make_rx_response(netif_t *netif, if (st < 0) resp->status = (s16)st; wmb(); - netif->rx->resp_prod = netif->rx_resp_prod = ++i; + netif->rx.rsp_prod_pvt = ++i; + RING_PUSH_RESPONSES(&netif->rx); mb(); /* Update producer before checking event threshold. */ - return (i == netif->rx->event); + return (i == netif->rx.sring->rsp_event); } static irqreturn_t netif_be_dbg(int irq, void *dev_id, struct pt_regs *regs) @@ -739,16 +759,16 @@ static irqreturn_t netif_be_dbg(int irq, void *dev_id, struct pt_regs *regs) netif = list_entry(ent, netif_t, list); printk(KERN_ALERT " %d: private(rx_req_cons=%08x " "rx_resp_prod=%08x\n", - i, netif->rx_req_cons, netif->rx_resp_prod); + i, netif->rx.req_cons, netif->rx.rsp_prod_pvt); printk(KERN_ALERT " tx_req_cons=%08x tx_resp_prod=%08x)\n", - netif->tx_req_cons, netif->tx_resp_prod); + netif->tx.req_cons, netif->tx.rsp_prod_pvt); printk(KERN_ALERT " shared(rx_req_prod=%08x " "rx_resp_prod=%08x\n", - netif->rx->req_prod, netif->rx->resp_prod); + netif->rx.sring->req_prod, netif->rx.sring->rsp_prod); printk(KERN_ALERT " rx_event=%08x tx_req_prod=%08x\n", - netif->rx->event, netif->tx->req_prod); + netif->rx.sring->rsp_event, netif->tx.sring->req_prod); printk(KERN_ALERT " tx_resp_prod=%08x, tx_event=%08x)\n", - netif->tx->resp_prod, netif->tx->event); + netif->tx.sring->rsp_prod, netif->tx.sring->rsp_event); i++; } @@ -764,7 +784,7 @@ static int __init netback_init(void) struct page *page; /* We can increase reservation by this much in net_rx_action(). */ - balloon_update_driver_allowance(NETIF_RX_RING_SIZE); + balloon_update_driver_allowance(NET_RX_RING_SIZE); skb_queue_head_init(&rx_queue); skb_queue_head_init(&tx_queue); diff --git a/linux-2.6-xen-sparse/drivers/xen/netfront/netfront.c b/linux-2.6-xen-sparse/drivers/xen/netfront/netfront.c index a3efed0d05..f773df408f 100644 --- a/linux-2.6-xen-sparse/drivers/xen/netfront/netfront.c +++ b/linux-2.6-xen-sparse/drivers/xen/netfront/netfront.c @@ -61,6 +61,9 @@ #define GRANT_INVALID_REF 0 +#define NET_TX_RING_SIZE __RING_SIZE((netif_tx_sring_t *)0, PAGE_SIZE) +#define NET_RX_RING_SIZE __RING_SIZE((netif_rx_sring_t *)0, PAGE_SIZE) + #ifndef __GFP_NOWARN #define __GFP_NOWARN 0 #endif @@ -76,22 +79,9 @@ /* Allow headroom on each rx pkt for Ethernet header, alignment padding, ... */ #define RX_HEADROOM 200 -/* - * If the backend driver is pipelining transmit requests then we can be very - * aggressive in avoiding new-packet notifications -- only need to send a - * notification if there are no outstanding unreceived responses. - * If the backend may be buffering our transmit buffers for any reason then we - * are rather more conservative. - */ -#ifdef CONFIG_XEN_NETDEV_FRONTEND_PIPELINED_TRANSMITTER -#define TX_TEST_IDX resp_prod /* aggressive: any outstanding responses? */ -#else -#define TX_TEST_IDX req_cons /* conservative: not seen all our requests? */ -#endif - -static unsigned long rx_pfn_array[NETIF_RX_RING_SIZE]; -static multicall_entry_t rx_mcl[NETIF_RX_RING_SIZE+1]; -static mmu_update_t rx_mmu[NETIF_RX_RING_SIZE]; +static unsigned long rx_pfn_array[NET_RX_RING_SIZE]; +static multicall_entry_t rx_mcl[NET_RX_RING_SIZE+1]; +static mmu_update_t rx_mmu[NET_RX_RING_SIZE]; struct netfront_info { @@ -99,11 +89,10 @@ struct netfront_info struct net_device *netdev; struct net_device_stats stats; - NETIF_RING_IDX rx_resp_cons, tx_resp_cons; unsigned int tx_full; - netif_tx_interface_t *tx; - netif_rx_interface_t *rx; + netif_tx_front_ring_t tx; + netif_rx_front_ring_t rx; spinlock_t tx_lock; spinlock_t rx_lock; @@ -124,7 +113,7 @@ struct netfront_info /* Receive-ring batched refills. */ #define RX_MIN_TARGET 8 -#define RX_MAX_TARGET NETIF_RX_RING_SIZE +#define RX_MAX_TARGET NET_RX_RING_SIZE int rx_min_target, rx_max_target, rx_target; struct sk_buff_head rx_batch; @@ -132,13 +121,13 @@ struct netfront_info * {tx,rx}_skbs store outstanding skbuffs. The first entry in each * array is an index into a chain of free entries. */ - struct sk_buff *tx_skbs[NETIF_TX_RING_SIZE+1]; - struct sk_buff *rx_skbs[NETIF_RX_RING_SIZE+1]; + struct sk_buff *tx_skbs[NET_TX_RING_SIZE+1]; + struct sk_buff *rx_skbs[NET_RX_RING_SIZE+1]; grant_ref_t gref_tx_head; - grant_ref_t grant_tx_ref[NETIF_TX_RING_SIZE + 1]; + grant_ref_t grant_tx_ref[NET_TX_RING_SIZE + 1]; grant_ref_t gref_rx_head; - grant_ref_t grant_rx_ref[NETIF_TX_RING_SIZE + 1]; + grant_ref_t grant_rx_ref[NET_TX_RING_SIZE + 1]; struct xenbus_device *xbdev; int tx_ring_ref; @@ -337,37 +326,45 @@ again: static int setup_device(struct xenbus_device *dev, struct netfront_info *info) { + netif_tx_sring_t *txs; + netif_rx_sring_t *rxs; int err; struct net_device *netdev = info->netdev; info->tx_ring_ref = GRANT_INVALID_REF; info->rx_ring_ref = GRANT_INVALID_REF; - info->rx = NULL; - info->tx = NULL; + info->rx.sring = NULL; + info->tx.sring = NULL; info->irq = 0; - info->tx = (netif_tx_interface_t *)__get_free_page(GFP_KERNEL); - if (!info->tx) { + txs = (netif_tx_sring_t *)__get_free_page(GFP_KERNEL); + if (!txs) { err = -ENOMEM; xenbus_dev_fatal(dev, err, "allocating tx ring page"); goto fail; } - info->rx = (netif_rx_interface_t *)__get_free_page(GFP_KERNEL); - if (!info->rx) { + rxs = (netif_rx_sring_t *)__get_free_page(GFP_KERNEL); + if (!rxs) { err = -ENOMEM; xenbus_dev_fatal(dev, err, "allocating rx ring page"); goto fail; } - memset(info->tx, 0, PAGE_SIZE); - memset(info->rx, 0, PAGE_SIZE); + memset(txs, 0, PAGE_SIZE); + memset(rxs, 0, PAGE_SIZE); info->backend_state = BEST_DISCONNECTED; - err = xenbus_grant_ring(dev, virt_to_mfn(info->tx)); + SHARED_RING_INIT(txs); + FRONT_RING_INIT(&info->tx, txs, PAGE_SIZE); + + SHARED_RING_INIT(rxs); + FRONT_RING_INIT(&info->rx, rxs, PAGE_SIZE); + + err = xenbus_grant_ring(dev, virt_to_mfn(txs)); if (err < 0) goto fail; info->tx_ring_ref = err; - err = xenbus_grant_ring(dev, virt_to_mfn(info->rx)); + err = xenbus_grant_ring(dev, virt_to_mfn(rxs)); if (err < 0) goto fail; info->rx_ring_ref = err; @@ -454,7 +451,7 @@ static int network_open(struct net_device *dev) np->user_state = UST_OPEN; network_alloc_rx_buffers(dev); - np->rx->event = np->rx_resp_cons + 1; + np->rx.sring->rsp_event = np->rx.rsp_cons + 1; netif_start_queue(dev); @@ -463,7 +460,7 @@ static int network_open(struct net_device *dev) static void network_tx_buf_gc(struct net_device *dev) { - NETIF_RING_IDX i, prod; + RING_IDX i, prod; unsigned short id; struct netfront_info *np = netdev_priv(dev); struct sk_buff *skb; @@ -472,11 +469,11 @@ static void network_tx_buf_gc(struct net_device *dev) return; do { - prod = np->tx->resp_prod; + prod = np->tx.sring->rsp_prod; rmb(); /* Ensure we see responses up to 'rp'. */ - for (i = np->tx_resp_cons; i != prod; i++) { - id = np->tx->ring[MASK_NETIF_TX_IDX(i)].resp.id; + for (i = np->tx.rsp_cons; i != prod; i++) { + id = RING_GET_RESPONSE(&np->tx, i)->id; skb = np->tx_skbs[id]; if (unlikely(gnttab_query_foreign_access( np->grant_tx_ref[id]) != 0)) { @@ -494,7 +491,7 @@ static void network_tx_buf_gc(struct net_device *dev) dev_kfree_skb_irq(skb); } - np->tx_resp_cons = prod; + np->tx.rsp_cons = prod; /* * Set a new event, then check for race with update of tx_cons. @@ -504,12 +501,14 @@ static void network_tx_buf_gc(struct net_device *dev) * data is outstanding: in such cases notification from Xen is * likely to be the only kick that we'll get. */ - np->tx->event = prod + ((np->tx->req_prod - prod) >> 1) + 1; + np->tx.sring->rsp_event = + prod + ((np->tx.sring->req_prod - prod) >> 1) + 1; mb(); - } while (prod != np->tx->resp_prod); + } while (prod != np->tx.sring->rsp_prod); out: - if (np->tx_full && ((np->tx->req_prod - prod) < NETIF_TX_RING_SIZE)) { + if (np->tx_full && + ((np->tx.sring->req_prod - prod) < NET_TX_RING_SIZE)) { np->tx_full = 0; if (np->user_state == UST_OPEN) netif_wake_queue(dev); @@ -523,7 +522,7 @@ static void network_alloc_rx_buffers(struct net_device *dev) struct netfront_info *np = netdev_priv(dev); struct sk_buff *skb; int i, batch_target; - NETIF_RING_IDX req_prod = np->rx->req_prod; + RING_IDX req_prod = np->rx.req_prod_pvt; struct xen_memory_reservation reservation; grant_ref_t ref; @@ -536,7 +535,7 @@ static void network_alloc_rx_buffers(struct net_device *dev) * allocator, so should reduce the chance of failed allocation requests * both for ourself and for other kernel subsystems. */ - batch_target = np->rx_target - (req_prod - np->rx_resp_cons); + batch_target = np->rx_target - (req_prod - np->rx.rsp_cons); for (i = skb_queue_len(&np->rx_batch); i < batch_target; i++) { skb = alloc_xen_skb(dev->mtu + RX_HEADROOM); if (skb == NULL) @@ -558,13 +557,13 @@ static void network_alloc_rx_buffers(struct net_device *dev) np->rx_skbs[id] = skb; - np->rx->ring[MASK_NETIF_RX_IDX(req_prod + i)].req.id = id; + RING_GET_REQUEST(&np->rx, req_prod + i)->id = id; ref = gnttab_claim_grant_reference(&np->gref_rx_head); BUG_ON((signed short)ref < 0); np->grant_rx_ref[id] = ref; gnttab_grant_foreign_transfer_ref(ref, np->xbdev->otherend_id); - np->rx->ring[MASK_NETIF_RX_IDX(req_prod + i)].req.gref = ref; + RING_GET_REQUEST(&np->rx, req_prod + i)->gref = ref; rx_pfn_array[i] = virt_to_mfn(skb->head); /* Remove this page from map before passing back to Xen. */ @@ -599,10 +598,11 @@ static void network_alloc_rx_buffers(struct net_device *dev) panic("Unable to reduce memory reservation\n"); /* Above is a suitable barrier to ensure backend will see requests. */ - np->rx->req_prod = req_prod + i; + np->rx.req_prod_pvt = req_prod + i; + RING_PUSH_REQUESTS(&np->rx); /* Adjust our fill target if we risked running out of buffers. */ - if (((req_prod - np->rx->resp_prod) < (np->rx_target / 4)) && + if (((req_prod - np->rx.sring->rsp_prod) < (np->rx_target / 4)) && ((np->rx_target *= 2) > np->rx_max_target)) np->rx_target = np->rx_max_target; } @@ -613,7 +613,7 @@ static int network_start_xmit(struct sk_buff *skb, struct net_device *dev) unsigned short id; struct netfront_info *np = netdev_priv(dev); netif_tx_request_t *tx; - NETIF_RING_IDX i; + RING_IDX i; grant_ref_t ref; unsigned long mfn; @@ -643,12 +643,12 @@ static int network_start_xmit(struct sk_buff *skb, struct net_device *dev) goto drop; } - i = np->tx->req_prod; + i = np->tx.req_prod_pvt; id = GET_ID_FROM_FREELIST(np->tx_skbs); np->tx_skbs[id] = skb; - tx = &np->tx->ring[MASK_NETIF_TX_IDX(i)].req; + tx = RING_GET_REQUEST(&np->tx, i); tx->id = id; ref = gnttab_claim_grant_reference(&np->gref_tx_head); @@ -662,11 +662,12 @@ static int network_start_xmit(struct sk_buff *skb, struct net_device *dev) tx->csum_blank = (skb->ip_summed == CHECKSUM_HW); wmb(); /* Ensure that backend will see the request. */ - np->tx->req_prod = i + 1; + np->tx.req_prod_pvt = i + 1; + RING_PUSH_REQUESTS(&np->tx); network_tx_buf_gc(dev); - if ((i - np->tx_resp_cons) == (NETIF_TX_RING_SIZE - 1)) { + if (RING_FULL(&np->tx)) { np->tx_full = 1; netif_stop_queue(dev); } @@ -678,8 +679,10 @@ static int network_start_xmit(struct sk_buff *skb, struct net_device *dev) /* Only notify Xen if we really have to. */ mb(); - if (np->tx->TX_TEST_IDX == i) + if (np->tx.sring->server_is_sleeping) { + np->tx.sring->server_is_sleeping = 0; notify_remote_via_irq(np->irq); + } return 0; @@ -699,7 +702,7 @@ static irqreturn_t netif_int(int irq, void *dev_id, struct pt_regs *ptregs) network_tx_buf_gc(dev); spin_unlock_irqrestore(&np->tx_lock, flags); - if ((np->rx_resp_cons != np->rx->resp_prod) && + if (RING_HAS_UNCONSUMED_RESPONSES(&np->rx) && (np->user_state == UST_OPEN)) netif_rx_schedule(dev); @@ -712,7 +715,7 @@ static int netif_poll(struct net_device *dev, int *pbudget) struct netfront_info *np = netdev_priv(dev); struct sk_buff *skb, *nskb; netif_rx_response_t *rx; - NETIF_RING_IDX i, rp; + RING_IDX i, rp; mmu_update_t *mmu = rx_mmu; multicall_entry_t *mcl = rx_mcl; int work_done, budget, more_to_do = 1; @@ -732,13 +735,13 @@ static int netif_poll(struct net_device *dev, int *pbudget) if ((budget = *pbudget) > dev->quota) budget = dev->quota; - rp = np->rx->resp_prod; + rp = np->rx.sring->rsp_prod; rmb(); /* Ensure we see queued responses up to 'rp'. */ - for (i = np->rx_resp_cons, work_done = 0; + for (i = np->rx.rsp_cons, work_done = 0; (i != rp) && (work_done < budget); i++, work_done++) { - rx = &np->rx->ring[MASK_NETIF_RX_IDX(i)].resp; + rx = RING_GET_RESPONSE(&np->rx, i); /* * This definitely indicates a bug, either in this driver or @@ -756,10 +759,11 @@ static int netif_poll(struct net_device *dev, int *pbudget) if (net_ratelimit()) WPRINTK("Unfulfilled rx req (id=%d, st=%d).\n", rx->id, rx->status); - np->rx->ring[MASK_NETIF_RX_IDX(np->rx->req_prod)]. - req.id = rx->id; + RING_GET_REQUEST(&np->rx, np->rx.req_prod_pvt)->id = + rx->id; wmb(); - np->rx->req_prod++; + np->rx.req_prod_pvt++; + RING_PUSH_REQUESTS(&np->rx); work_done--; continue; } @@ -861,11 +865,11 @@ static int netif_poll(struct net_device *dev, int *pbudget) dev->last_rx = jiffies; } - np->rx_resp_cons = i; + np->rx.rsp_cons = i; /* If we get a callback with very few responses, reduce fill target. */ /* NB. Note exponential increase, linear decrease. */ - if (((np->rx->req_prod - np->rx->resp_prod) > + if (((np->rx.req_prod_pvt - np->rx.sring->rsp_prod) > ((3*np->rx_target) / 4)) && (--np->rx_target < np->rx_min_target)) np->rx_target = np->rx_min_target; @@ -878,11 +882,11 @@ static int netif_poll(struct net_device *dev, int *pbudget) if (work_done < budget) { local_irq_save(flags); - np->rx->event = i + 1; + np->rx.sring->rsp_event = i + 1; /* Deal with hypervisor racing our resetting of rx_event. */ mb(); - if (np->rx->resp_prod == i) { + if (np->rx.sring->rsp_prod == i) { __netif_rx_complete(dev); more_to_do = 0; } @@ -925,8 +929,8 @@ static void network_connect(struct net_device *dev) /* Recovery procedure: */ /* Step 1: Reinitialise variables. */ - np->rx_resp_cons = np->tx_resp_cons = np->tx_full = 0; - np->rx->event = np->tx->event = 1; + np->tx_full = 0; + np->rx.sring->rsp_event = np->tx.sring->rsp_event = 1; /* * Step 2: Rebuild the RX and TX ring contents. @@ -946,13 +950,14 @@ static void network_connect(struct net_device *dev) * to avoid this but maybe it doesn't matter so much given the * interface has been down. */ - for (requeue_idx = 0, i = 1; i <= NETIF_TX_RING_SIZE; i++) { + for (requeue_idx = 0, i = 1; i <= NET_TX_RING_SIZE; i++) { if ((unsigned long)np->tx_skbs[i] < __PAGE_OFFSET) continue; skb = np->tx_skbs[i]; - tx = &np->tx->ring[requeue_idx++].req; + tx = RING_GET_REQUEST(&np->tx, requeue_idx); + requeue_idx++; tx->id = i; gnttab_grant_foreign_access_ref( @@ -968,21 +973,23 @@ static void network_connect(struct net_device *dev) np->stats.tx_packets++; } wmb(); - np->tx->req_prod = requeue_idx; + np->tx.req_prod_pvt = requeue_idx; + RING_PUSH_REQUESTS(&np->tx); /* Rebuild the RX buffer freelist and the RX ring itself. */ - for (requeue_idx = 0, i = 1; i <= NETIF_RX_RING_SIZE; i++) { + for (requeue_idx = 0, i = 1; i <= NET_RX_RING_SIZE; i++) { if ((unsigned long)np->rx_skbs[i] < __PAGE_OFFSET) continue; gnttab_grant_foreign_transfer_ref( np->grant_rx_ref[i], np->xbdev->otherend_id); - np->rx->ring[requeue_idx].req.gref = + RING_GET_REQUEST(&np->rx, requeue_idx)->gref = np->grant_rx_ref[i]; - np->rx->ring[requeue_idx].req.id = i; + RING_GET_REQUEST(&np->rx, requeue_idx)->id = i; requeue_idx++; } wmb(); - np->rx->req_prod = requeue_idx; + np->rx.req_prod_pvt = requeue_idx; + RING_PUSH_REQUESTS(&np->rx); /* * Step 3: All public and private state should now be sane. Get @@ -1066,25 +1073,25 @@ static int create_netdev(int handle, struct xenbus_device *dev, np->rx_max_target = RX_MAX_TARGET; /* Initialise {tx,rx}_skbs as a free chain containing every entry. */ - for (i = 0; i <= NETIF_TX_RING_SIZE; i++) { + for (i = 0; i <= NET_TX_RING_SIZE; i++) { np->tx_skbs[i] = (void *)((unsigned long) i+1); np->grant_tx_ref[i] = GRANT_INVALID_REF; } - for (i = 0; i <= NETIF_RX_RING_SIZE; i++) { + for (i = 0; i <= NET_RX_RING_SIZE; i++) { np->rx_skbs[i] = (void *)((unsigned long) i+1); np->grant_rx_ref[i] = GRANT_INVALID_REF; } /* A grant for every tx ring slot */ - if (gnttab_alloc_grant_references(NETIF_TX_RING_SIZE, + if (gnttab_alloc_grant_references(NET_TX_RING_SIZE, &np->gref_tx_head) < 0) { printk(KERN_ALERT "#### netfront can't alloc tx grant refs\n"); err = -ENOMEM; goto exit; } /* A grant for every rx ring slot */ - if (gnttab_alloc_grant_references(NETIF_RX_RING_SIZE, + if (gnttab_alloc_grant_references(NET_RX_RING_SIZE, &np->gref_rx_head) < 0) { printk(KERN_ALERT "#### netfront can't alloc rx grant refs\n"); gnttab_free_grant_references(np->gref_tx_head); @@ -1212,12 +1219,12 @@ static void netif_disconnect_backend(struct netfront_info *info) spin_unlock(&info->rx_lock); spin_unlock_irq(&info->tx_lock); - end_access(info->tx_ring_ref, info->tx); - end_access(info->rx_ring_ref, info->rx); + end_access(info->tx_ring_ref, info->tx.sring); + end_access(info->rx_ring_ref, info->rx.sring); info->tx_ring_ref = GRANT_INVALID_REF; info->rx_ring_ref = GRANT_INVALID_REF; - info->tx = NULL; - info->rx = NULL; + info->tx.sring = NULL; + info->rx.sring = NULL; if (info->irq) unbind_from_irqhandler(info->irq, info->netdev); diff --git a/xen/include/public/io/netif.h b/xen/include/public/io/netif.h index 498cbd1e97..2f899a3b65 100644 --- a/xen/include/public/io/netif.h +++ b/xen/include/public/io/netif.h @@ -9,6 +9,8 @@ #ifndef __XEN_PUBLIC_IO_NETIF_H__ #define __XEN_PUBLIC_IO_NETIF_H__ +#include "ring.h" + typedef struct netif_tx_request { grant_ref_t gref; /* Reference to buffer page */ uint16_t offset:15; /* Offset within buffer page */ @@ -35,57 +37,12 @@ typedef struct { } netif_rx_response_t; /* - * We use a special capitalised type name because it is _essential_ that all - * arithmetic on indexes is done on an integer type of the correct size. - */ -typedef uint32_t NETIF_RING_IDX; - -/* - * Ring indexes are 'free running'. That is, they are not stored modulo the - * size of the ring buffer. The following macros convert a free-running counter - * into a value that can directly index a ring-buffer array. + * Generate netif ring structures and types. */ -#define MASK_NETIF_RX_IDX(_i) ((_i)&(NETIF_RX_RING_SIZE-1)) -#define MASK_NETIF_TX_IDX(_i) ((_i)&(NETIF_TX_RING_SIZE-1)) - -#define NETIF_TX_RING_SIZE 256 -#define NETIF_RX_RING_SIZE 256 - -/* This structure must fit in a memory page. */ -typedef struct netif_tx_interface { - /* - * Frontend places packets into ring at tx_req_prod. - * Frontend receives event when tx_resp_prod passes tx_event. - * 'req_cons' is a shadow of the backend's request consumer -- the frontend - * may use it to determine if all queued packets have been seen by the - * backend. - */ - NETIF_RING_IDX req_prod; - NETIF_RING_IDX req_cons; - NETIF_RING_IDX resp_prod; - NETIF_RING_IDX event; - union { - netif_tx_request_t req; - netif_tx_response_t resp; - } ring[NETIF_TX_RING_SIZE]; -} netif_tx_interface_t; -/* This structure must fit in a memory page. */ -typedef struct netif_rx_interface { - /* - * Frontend places empty buffers into ring at rx_req_prod. - * Frontend receives event when rx_resp_prod passes rx_event. - */ - NETIF_RING_IDX req_prod; - NETIF_RING_IDX resp_prod; - NETIF_RING_IDX event; - union { - netif_rx_request_t req; - netif_rx_response_t resp; - } ring[NETIF_RX_RING_SIZE]; -} netif_rx_interface_t; +DEFINE_RING_TYPES(netif_tx, netif_tx_request_t, netif_tx_response_t); +DEFINE_RING_TYPES(netif_rx, netif_rx_request_t, netif_rx_response_t); -/* Descriptor status values */ #define NETIF_RSP_DROPPED -2 #define NETIF_RSP_ERROR -1 #define NETIF_RSP_OKAY 0 diff --git a/xen/include/public/io/ring.h b/xen/include/public/io/ring.h index f52ccdc392..1f333850b3 100644 --- a/xen/include/public/io/ring.h +++ b/xen/include/public/io/ring.h @@ -1,3 +1,6 @@ + + + /* * Shared producer-consumer ring macros. * Tim Deegan and Andrew Warfield November 2004. @@ -22,7 +25,7 @@ typedef unsigned int RING_IDX; * power of two (so we can mask with (size-1) to loop around). */ #define __RING_SIZE(_s, _sz) \ - (__RD32(((_sz) - 2*sizeof(RING_IDX)) / sizeof((_s)->ring[0]))) + (__RD32(((_sz) - (long)&(_s)->ring + (long)(_s)) / sizeof((_s)->ring[0]))) /* * Macros to make the correct C datatypes for a new kind of ring. @@ -65,6 +68,8 @@ union __name##_sring_entry { \ struct __name##_sring { \ RING_IDX req_prod; \ RING_IDX rsp_prod; \ + RING_IDX rsp_event; /* notify client when rsp_prod == rsp_event */ \ + uint8_t server_is_sleeping; /* notify server to kick off work */ \ union __name##_sring_entry ring[1]; /* variable-length */ \ }; \ \ -- 2.30.2